import config from "../src/core/config";

/* eslint-disable */
function defineReactive(obj, key, value) {
  observe(value);
  const dep = new Dep();
  Object.defineProperty(obj, key, {
    get() {
      console.log("get", key, value);
      //   依赖收集建立
      Dep.target && dep.addDep(Dep.target);
      return value;
    },
    set(newVal) {
      if (newVal != value) {
        console.log("set", key, newVal);
        observe(newVal);
        value = newVal;
        // 通知更新
        dep.notify();
      }
    },
  });
}

function proxy(vm) {
  Object.keys(vm.$data).forEach((key) => {
    Object.defineProperty(vm, key, {
      get() {
        return vm.$data[key];
      },
      set(newVal) {
        vm.$data[key] = newVal;
      },
    });
  });
}

function observe(obj) {
  if (typeof obj != "object" || obj == null) {
    return obj;
  }
  Object.keys(obj).forEach((key) => {
    defineReactive(obj, key, obj[key]);
  });
}

class Vue {
  constructor(options) {
    this.$options = options;
    this.$data =
      typeof options.data === "function"
        ? options.data.call(this)
        : options.data;

    // 递归生成data的getter、setter
    observe(this.$data);

    // this代理data中的key
    proxy(this);

    // 编译模板
    new Complie(options.el, this);
  }
}
class Complie {
  constructor(el, vm) {
    this.$vm = vm;
    let dom = document.querySelector(el);
    this.complie(dom);
  }
  complie(el) {
    let childNodes = el.childNodes;
    childNodes.forEach((node) => {
      if (this.isElement(node)) {
        const attrs = node.attributes;

        [...attrs].forEach(({ name, value }) => {
          if (this.isDir(name)) {
            const dir = name.substring(2);
            this[dir] && this[dir](node, value);
          }
        });
        if (node.childNodes.length) {
          this.complie(node);
        }
      } else if (this.isInter(node)) {
        this.complieText(node);
        // console.log("编译插值", node.textContent);
      }
    });
  }
  isElement(node) {
    return node.nodeType == 1;
  }
  // 插值
  isInter(node) {
    return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent);
  }
  //   处理所有动态绑定 dir指令名称
  update(node, exp, dir) {
    const fn = this[dir + "Updator"];
    fn && fn(node, this.$vm[exp]);
    new Watcher(this.$vm, exp, (val) => {
      fn && fn(node, val);
    });
  }
  text(node, exp) {
    this.update(node, exp, "text");
  }
  html(node, exp) {
    this.update(node, exp, "html");
  }
  textUpdator(node, val) {
    node.textContent = val;
  }
  htmlUpdator(node, val) {
    node.innerHTML = val;
  }
  complieText(node) {
    this.update(node, RegExp.$1, "text");
  }
  isDir(attrName) {
    return attrName.startsWith("k-");
  }
}

// const watchers = [];
//
class Watcher {
  constructor(vm, key, getter) {
    this.vm = vm;
    this.key = key;
    this.getter = getter;
    // watchers.push(this);
  }
  // 执行更新
  run() {
    this.get();
  }
  get() {
    // 触发依赖收集
    Dep.target = this; // 设定需要依赖收集的目标
    this.getter.call(this.vm);
    Dep.target = null;
  }
  update() {
    // computed
    if (this.lazy) {
      this.dirty = true;
      // $watch sync选项
    } else if (this.sync) {
      this.run();
    } else {
      queueWatcher(this);
    }
  }
}
// Dep和响应式属性key之间一一对应 负责通知watcher更新
class Dep {
  constructor() {
    this.deps = [];
  }
  addDep(w) {
    this.deps.push(w);
  }
  notify() {
    this.deps.forEach((w) => w.update());
  }
}

// 需要执行更新的任务,其中包含用户使用$nextTick添加的回调以及组件watcher更新的回调
const callbacks = []; 

// 需要执行更新操作的watcher
const queue = []; 

// watcher的id与是否入队的映射关系
const has = {}; 


let pending = false;
let flushing = false;

// 执行任务队列所有回调
function flushCallbacks() {
  pending = false;
  let copies = cbs.slice(0);
  copies.forEach((cb) => cb());
}


// 刷新watcher
// 从queue中取出需要更新的watcher，并执行它的更新方法run -> get -> getter
function flushSchedulerQueue() {
  queue.forEach((w) => w.run());
}


// 将需要异步处理的更新函数放到 callbacks数组中
// 用户如果这样使用 this.$nextTick(customFunc)
// [() => {flushShedulerQueue()}, ()=>{customFunc()}  ]
// 便于后续在同步代码完成后，统一执行
function nextTick(cb) {
  // 封装一个可以处理异常的高阶函数
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call();
      } catch (e) {
        console.error(e);
      }
    }
  });

  if (!pending) {
    pending = true;
    timeFunc();
  }
}

// watcher入队
// 便于在后续，知道哪些watcher需要执行更新
function queueWatcher(watcher) {
  // 相同watcher更新避免重复
  if (!has[watcher.id]) {
    queue.push(watcher);

    nextTick(flushSchedulerQueue);
  }
}


// 根据不同环境使用不同异步处理方式
let timeFunc;

if (typeof Promise) {
  timeFunc = () => {
    Promise.resolve().then(flushCallbacks);
  };
} else if (typeof MutationObserver) {
  let count = 1;
  let text = document.createTextNode(count);
  let ob = new MutationObserver(flushCallbacks);
  ob.observe(text, { characterData: true });
  timeFunc = () => {
    count = (count + 1) % 2;
  };
} else if (typeof setImmediate != "undefined") {
  timeFunc = () => {
    setImmediate(flushCallbacks);
  };
} else {
  timeFunc = () => {
    setTimeout(flushCallbacks);
  };
}
